home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / amitcp / amitcp-src-22.lha / AmiTCP-2.2 / src / util / ping / ping.c next >
Encoding:
C/C++ Source or Header  |  1993-10-20  |  35.6 KB  |  1,301 lines

  1. /*
  2.  * ping.c
  3.  *
  4.  * Created      : Thu Apr 15 09:48:07 1993 ppessi
  5.  * Last modified: Wed Oct 20 16:59:14 1993 jraja
  6.  */
  7.  
  8. static const char version[] = "$VER: ping 2.1 (21.10.93)";
  9.  
  10. char copyright[] =
  11. "@(#) Copyright © 1983 The Regents of the University of California.\n"
  12.                       "All rights reserved.\n"
  13.      "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  14.                       "Helsinki University of Technology, Finland.\n"
  15.                       "All rights reserved.\n";
  16.  
  17. /****** netutil.doc/ping ****************************************************
  18. *
  19. *   NAME
  20. *       ping - send ICMP ECHO_REQUEST packets to network hosts
  21. *   
  22. *   SYNOPSIS
  23. *       ping [-dfnqrvR] [-c count] [-i wait] [-l preload] [-p pattern] 
  24. *            [-s packetsize]
  25. *   
  26. *   DESCRIPTION
  27. *       Ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
  28. *       elicit an ICMP ECHO_RESPONSE from a host or gateway.  ECHO_REQUEST
  29. *       datagrams (``pings'') have an IP and ICMP header, followed by a
  30. *       ``struct timeval'' and then an arbitrary number of ``pad'' bytes
  31. *       used to fill out the packet.  The options are as follows: Other
  32. *       options are:
  33. *   
  34. *       -c count
  35. *               Stop after sending (and receiving) count ECHO_RESPONSE
  36. *               packets.
  37. *   
  38. *       -d      Set the SO_DEBUG option on the socket being used.
  39. *   
  40. *       -f      Flood ping.  Outputs packets as fast as they come back or
  41. *               one hundred times per second, whichever is more.  For every
  42. *               ECHO_REQUEST sent a period ``.'' is printed, while for ever
  43. *               ECHO_REPLY received a backspace is printed.  This provides a
  44. *               rapid display of how many packets are being dropped.  Only
  45. *               the super-user may use this option.  This can be very hard
  46. *               on a network and should be used with caution.
  47. *   
  48. *       -i wait
  49. *               Wait wait seconds between sending each packet. The default
  50. *               is to wait for one second between each packet.  This option
  51. *               is incompatible with the -f option.
  52. *   
  53. *       -l preload
  54. *               If preload is specified, ping sends that many packets as
  55. *               fast as possible before falling into its normal mode of
  56. *               behavior.
  57. *   
  58. *       -n      Numeric output only.  No attempt will be made to lookup
  59. *               symbolic names for host addresses.
  60. *   
  61. *       -p pattern
  62. *               You may specify up to 16 ``pad'' bytes to fill out the
  63. *               packet you send.  This is useful for diagnosing
  64. *               data-dependent problems in a network.  For example, ``-p
  65. *               ff'' will cause the sent packet to be filled with all ones.
  66. *   
  67. *       -q      Quiet output.  Nothing is displayed except the summary lines
  68. *               at startup time and when finished.
  69. *   
  70. *       -R      Record route.  Includes the RECORD_ROUTE option in the
  71. *               ECHO_REQUEST packet and displays the route buffer on
  72. *               returned packets.  Note that the IP header is only large
  73. *               enough for nine such routes.  Many hosts ignore or discard
  74. *               this option.
  75. *   
  76. *       -r      Bypass the normal routing tables and send directly to a host
  77. *               on an attached network.  If the host is not on a
  78. *               directly-attached network, an error is returned.  This
  79. *               option can be used to ping a local host through an interface
  80. *               that has no route through it.
  81. *   
  82. *       -s packetsize
  83. *               Specifies the number of data bytes to be sent.  The default
  84. *               is 56, which translates into 64 ICMP data bytes when
  85. *               combined with the 8 bytes of ICMP header data.
  86. *   
  87. *       -v      Verbose output.  ICMP packets other than ECHO_RESPONSE that
  88. *               are received are listed.
  89. *   
  90. *       When using ping for fault isolation, it should first be run on the
  91. *       local host, to verify that the local network interface is up and
  92. *       running.  Then, hosts and gateways further and further away should
  93. *       be ``pinged''.  Round-trip times and packet loss statistics are
  94. *       computed.  If duplicate packets are received, they are not included
  95. *       in the packet loss calculation, although the round trip time of
  96. *       these packets is used in calculating the minimum/average/maximum
  97. *       round-trip time numbers.  When the specified number of packets have
  98. *       been sent (and received) or if the program is terminated with a
  99. *       SIGINT, a brief summary is displayed.
  100. *   
  101. *       This program is intended for use in network testing, measurement and
  102. *       management.  Because of the load it can impose on the network, it is
  103. *       unwise to use ping during normal operations or from automated
  104. *       scripts.
  105. *   
  106. *   ICMP PACKET DETAILS 
  107. *       An IP header without options is 20 bytes.  An ICMP ECHO_REQUEST
  108. *       packet contains an additional 8 bytes worth of ICMP header followed
  109. *       by an arbitrary amount of data.  When a packetsize is given, this
  110. *       indicated the size of this extra piece of data (the default is 56).
  111. *       Thus the amount of data received inside of an IP packet of type ICMP
  112. *       ECHO_REPLY will always be 8 bytes more than the requested data space
  113. *       (the ICMP header).
  114. *   
  115. *       If the data space is at least eight bytes large, ping uses the first
  116. *       eight bytes of this space to include a timestamp which it uses in
  117. *       the computation of round trip times.  If less than eight bytes of
  118. *       pad are specified, no round trip times are given.
  119. *   
  120. *   DUPLICATE AND DAMAGED PACKETS
  121. *       Ping will report duplicate and damaged packets.  Duplicate packets
  122. *       should never occur, and seem to be caused by inappropriate
  123. *       link-level retransmissions.  Duplicates may occur in many situations
  124. *       and are rarely (if ever) a good sign, although the presence of low
  125. *       levels of duplicates may not always be cause for alarm.
  126. *   
  127. *       Damaged packets are obviously serious cause for alarm and often
  128. *       indicate broken hardware somewhere in the ping packet's path (in the
  129. *       network or in the hosts).
  130. *   
  131. *   TRYING DIFFERENT DATA PATTERNS
  132. *       The (inter)network layer should never treat packets differently
  133. *       depending on the data contained in the data portion.  Unfortunately,
  134. *       data-dependent problems have been known to sneak into networks and
  135. *       remain undetected for long periods of time.  In many cases the
  136. *       particular pattern that will have problems is something that doesn't
  137. *       have sufficient ``transitions'', such as all ones or all zeros, or a
  138. *       pattern right at the edge, such as almost all zeros.  It isn't
  139. *       necessarily enough to specify a data pattern of all zeros (for
  140. *       example) on the command line because the pattern that is of interest
  141. *       is at the data link level, and the relationship between what you
  142. *       type and what the controllers transmit can be complicated.
  143. *   
  144. *       This means that if you have a data-dependent problem you will
  145. *       probably have to do a lot of testing to find it.  If you are lucky,
  146. *       you may manage to find a file that either can't be sent across your
  147. *       network or that takes much longer to transfer than other similar
  148. *       length files.  You can then examine this file for repeated patterns
  149. *       that you can test using the -p option of ping.
  150. *   
  151. *   TTL DETAILS
  152. *       The TTL value of an IP packet represents the maximum number of IP
  153. *       routers that the packet can go through before being thrown away.  In
  154. *       current practice you can expect each router in the Internet to
  155. *       decrement the TTL field by exactly one.
  156. *   
  157. *       The TCP/IP specification states that the TTL field for TCP packets
  158. *       should be set to 60, but many systems use smaller values (4.3 BSD
  159. *       uses 30, 4.2 used 15). The AmiTCP/IP uses normally TTL value 30.
  160. *   
  161. *       The maximum possible value of this field is 255, and most systems
  162. *       set the TTL field of ICMP ECHO_REQUEST packets to 255.  This is why
  163. *       you will find you can ``ping'' some hosts, but not reach them with
  164. *       telnet or ftp.
  165. *   
  166. *       In normal operation ping prints the ttl value from the packet it re-
  167. *       ceives.  When a remote system receives a ping packet, it can do one
  168. *       of three things with the TTL field in its response:
  169. *   
  170. *       ·   Not change it; this is what Berkeley Unix systems did before the
  171. *           4.3BSD-Tahoe release.  In this case the TTL value in the
  172. *           received packet will be 255 minus the number of routers in the
  173. *           round-trip path.
  174. *   
  175. *       ·   Set it to 255; this is what AmiTCP/IP and current Berkeley Unix
  176. *           systems do.  In this case the TTL value in the received packet
  177. *           will be 255 minus the number of routers in the path from the
  178. *           remote system to the pinging host.
  179. *   
  180. *       ·   Set it to some other value.  Some machines use the same value
  181. *           for ICMP packets that they use for TCP packets, for example
  182. *           either 30 or 60.  Others may use completely wild values.
  183. *   
  184. *   BUGS
  185. *       Many Hosts and Gateways ignore the RECORD_ROUTE option.
  186. *   
  187. *       The maximum IP header length is too small for options like
  188. *       RECORD_ROUTE to be completely useful.  There's not much that that
  189. *       can be done about this, however.
  190. *   
  191. *       Flood pinging is not recommended in general, and flood pinging the
  192. *       broadcast address should only be done under very controlled
  193. *       conditions.
  194. *   
  195. *   SEE ALSO
  196. *       netstat,  ifconfig
  197. *   
  198. *   AUTHOR 
  199. *       The ping command originally appeared in 4.3BSD.
  200. *
  201. *****************************************************************************
  202. *
  203. */
  204.  
  205. /*
  206.  *            P I N G . C
  207.  *
  208.  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  209.  * measure round-trip-delays and packet loss across network paths.
  210.  *
  211.  * Author -
  212.  *    Mike Muuss
  213.  *    U. S. Army Ballistic Research Laboratory
  214.  *    December, 1983
  215.  *
  216.  * Status -
  217.  *    Public Domain.  Distribution Unlimited.
  218.  * Bugs -
  219.  *    More statistics could always be gathered.
  220.  */
  221.  
  222. #ifdef AMIGA
  223. #if __SASC
  224. #include <proto/socket.h>
  225. #elif __GNUC__
  226. #include <inline/socket.h>
  227. #else
  228. #include <clib/socket_protos.h>
  229. #endif
  230. #define ioctl IoctlSocket
  231.  
  232. /* Correct prototype for the CheckIO.
  233.  * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits) 
  234.  * instead of a pointer (32 bits)!)
  235.  */
  236. struct IORequest * CheckIO(struct IORequest *req);
  237.  
  238. #endif /* AMIGA */
  239.  
  240. #include <sys/param.h>
  241. #include <sys/socket.h>
  242. #include <sys/time.h>
  243.  
  244. #ifdef __SASC
  245. #include <signal.h>
  246. #else
  247. #include <sys/file.h>
  248. #include <sys/signal.h>
  249. #endif
  250.  
  251. #include <netinet/in_systm.h>
  252. #include <netinet/in.h>
  253. #include <netinet/ip.h>
  254. #include <netinet/ip_icmp.h>
  255. #include <netinet/ip_var.h>
  256. #include <netdb.h>
  257. #include <arpa/inet.h>
  258. /* #include <unistd.h> */
  259. #include <stdio.h>
  260. #include <ctype.h>
  261. #include <errno.h>
  262. #include <string.h>
  263.  
  264. #define    DEFDATALEN    (64 - 8)    /* default data length */
  265. #define    MAXIPLEN    60
  266. #define    MAXICMPLEN    76
  267. #define    MAXPACKET    (65536 - 60 - 8)/* max packet size */
  268. #define    MAXWAIT        10        /* max seconds to wait for response */
  269. #define    NROUTES        9        /* number of record route slots */
  270.  
  271. #define    A(bit)        rcvd_tbl[(bit)>>3]    /* identify byte in array */
  272. #define    B(bit)        (1 << ((bit) & 0x07))    /* identify bit in byte */
  273. #define    SET(bit)    (A(bit) |= B(bit))
  274. #define    CLR(bit)    (A(bit) &= (~B(bit)))
  275. #define    TST(bit)    (A(bit) & B(bit))
  276.  
  277. /* various options */
  278. int options;
  279. #define    F_FLOOD        0x001
  280. #define    F_INTERVAL    0x002
  281. #define    F_NUMERIC    0x004
  282. #define    F_PINGFILLED    0x008
  283. #define    F_QUIET        0x010
  284. #define    F_RROUTE    0x020
  285. #define    F_SO_DEBUG    0x040
  286. #define    F_SO_DONTROUTE    0x080
  287. #define    F_VERBOSE    0x100
  288.  
  289. /*
  290.  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
  291.  * number of received sequence numbers we can keep track of.  Change 128
  292.  * to 8192 for complete accuracy...
  293.  */
  294. #define    MAX_DUP_CHK    (8 * 128)
  295. int mx_dup_ck = MAX_DUP_CHK;
  296. char rcvd_tbl[MAX_DUP_CHK / 8];
  297.  
  298. struct sockaddr whereto;    /* who to ping */
  299. int datalen = DEFDATALEN;
  300. int s = -1;            /* socket file descriptor */
  301. u_char outpack[MAXPACKET];
  302. char BSPACE = '\b';        /* characters written for flood */
  303. char DOT = '.';
  304. char *hostname;
  305. long ident;            /* process id to identify our packets */
  306.  
  307. /* counters */
  308. long npackets;            /* max packets to transmit */
  309. long nreceived;            /* # of packets we got back */
  310. long nrepeats;            /* number of duplicates */
  311. long ntransmitted;        /* sequence # for outbound packets = #sent */
  312. int interval = 1;        /* interval between packets */
  313.  
  314. /* timing */
  315. int timing;            /* flag to do timing */
  316. long tmin = LONG_MAX;        /* minimum round trip time */
  317. long tmax;            /* maximum round trip time */
  318. u_long tsum;            /* sum of all times, for doing average */
  319.  
  320. char *pr_addr(u_long l);
  321. void catcher(void), pinger(void), finish(void), usage(void);
  322. void pr_pack(char *buf,    int cc,    struct sockaddr_in *from);
  323. void pr_icmph(struct icmp *icp);
  324. void pr_iph(struct ip *ip);
  325. void pr_retip(struct ip *ip);
  326. void fill(char *bp, char *patp);
  327. int in_cksum(u_short *addr, int len);
  328. void tvsub(register struct timeval *out, register struct timeval *in);
  329.  
  330. #ifdef AMIGA
  331. /* 
  332.  * Other Amiga dependent stuff
  333.  */
  334. #ifdef __SASC
  335. #include <clib/exec_protos.h>
  336. #include <pragmas/exec_sysbase_pragmas.h>
  337. extern struct ExecBase *SysBase;
  338. #endif
  339. #include <dos/dos.h>
  340.  
  341. #define getpid(x) ((ULONG)FindTask(NULL)) /* This is only for ident... */
  342.  
  343. struct MsgPort *timerport = NULL;
  344. struct timerequest *timermsg = NULL;
  345. BOOL notopen = TRUE;
  346. #define TimerBase (timermsg->tr_node.io_Device)
  347.  
  348. void 
  349. clean_timer(void)
  350. {
  351.   if (timermsg) {
  352.     if (!notopen) {
  353.       if (!CheckIO((struct IORequest*)timermsg)) {
  354.     AbortIO((struct IORequest*)timermsg);
  355.     WaitIO((struct IORequest*)timermsg);
  356.       }
  357.       CloseDevice((struct IORequest*)timermsg);
  358.       notopen = TRUE;
  359.     }
  360.     DeleteIORequest(timermsg);
  361.     timermsg = NULL;
  362.   } 
  363.   if (timerport) {
  364.     DeleteMsgPort(timerport);
  365.     timerport = NULL;
  366.   }
  367. }
  368. #endif
  369.  
  370. main(argc, argv)
  371.     int argc;
  372.     char **argv;
  373. {
  374.   extern int errno, optind;
  375.   extern char *optarg;
  376.   struct timeval timeout;
  377.   struct hostent *hp;
  378.   struct sockaddr_in *to;
  379.   struct protoent *proto;
  380.   register int i;
  381.   int ch, fdmask, hold, packlen, preload;
  382.   u_char *datap, *packet;
  383.   char *target, hnamebuf[MAXHOSTNAMELEN], *malloc();
  384. #ifdef IP_OPTIONS
  385.   char rspace[3 + 4 * NROUTES + 1]; /* record route space */
  386. #endif
  387. #ifdef AMIGA
  388.   ULONG timermask;
  389. #endif
  390.   preload = 0;
  391.   datap = &outpack[8 + sizeof(struct timeval)];
  392.   while ((ch = getopt(argc, argv, "Rc:dfh:i:l:np:qrs:v")) != EOF)
  393.     switch(ch) {
  394.     case 'c':
  395.       npackets = atoi(optarg);
  396.       if (npackets <= 0) {
  397.     (void)fprintf(stderr, "ping: bad number of packets to transmit.\n");
  398.     exit(1);
  399.       }
  400.       break;
  401.     case 'd':
  402.       options |= F_SO_DEBUG;
  403.       break;
  404.     case 'f':
  405. #ifndef AMIGA
  406.       if (getuid()) {
  407.     (void)fprintf(stderr, "ping: %s\n", strerror(EPERM));
  408.     exit(1);
  409.       }
  410. #endif
  411.       options |= F_FLOOD;
  412.       setbuf(stdout, (char *)NULL);
  413.       break;
  414.     case 'i':            /* wait between sending packets */
  415.       interval = atoi(optarg);
  416.       if (interval <= 0) {
  417.     (void)fprintf(stderr, "ping: bad timing interval.\n");
  418.     exit(1);
  419.       }
  420.       options |= F_INTERVAL;
  421.       break;
  422.     case 'l':
  423.       preload = atoi(optarg);
  424.       if (preload < 0) {
  425.     (void)fprintf(stderr, "ping: bad preload value.\n");
  426.     exit(1);
  427.       }
  428.       break;
  429.     case 'n':
  430.       options |= F_NUMERIC;
  431.       break;
  432.     case 'p':            /* fill buffer with user pattern */
  433.       options |= F_PINGFILLED;
  434.       fill((char *)datap, optarg);
  435.       break;
  436.     case 'q':
  437.       options |= F_QUIET;
  438.       break;
  439.     case 'R':
  440.       options |= F_RROUTE;
  441.       break;
  442.     case 'r':
  443.       options |= F_SO_DONTROUTE;
  444.       break;
  445.     case 's':            /* size of packet to send */
  446.       datalen = atoi(optarg);
  447.       if (datalen > MAXPACKET) {
  448.     (void)fprintf(stderr, "ping: packet size too large.\n");
  449.     exit(1);
  450.       }
  451.       if (datalen <= 0) {
  452.     (void)fprintf(stderr, "ping: illegal packet size.\n");
  453.     exit(1);
  454.       }
  455.       break;
  456.     case 'v':
  457.       options |= F_VERBOSE;
  458.       break;
  459.     default:
  460.       usage();
  461.     }
  462.   argc -= optind;
  463.   argv += optind;
  464.  
  465.   if (argc != 1)
  466.     usage();
  467.   target = *argv;
  468.  
  469.   bzero((char *)&whereto, sizeof(struct sockaddr));
  470.   to = (struct sockaddr_in *)&whereto;
  471.   to->sin_len = sizeof(*to);
  472.   to->sin_family = AF_INET;
  473.   to->sin_addr.s_addr = inet_addr(target);
  474.   if (to->sin_addr.s_addr != (u_int)-1)
  475.     hostname = target;
  476.   else {
  477.     hp = gethostbyname(target);
  478.     if (!hp) {
  479.       (void)fprintf(stderr, "ping: unknown host %s\n", target);
  480.       exit(1);
  481.     }
  482.     to->sin_family = hp->h_addrtype;
  483.     bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
  484.     (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
  485.     hostname = hnamebuf;
  486.   }
  487.  
  488.   if (options & F_FLOOD && options & F_INTERVAL) {
  489.     (void)fprintf(stderr, "ping: -f and -i incompatible options.\n");
  490.     exit(1);
  491.   }
  492.  
  493.   if (datalen >= sizeof(struct timeval)) /* can we time transfer */
  494.     timing = 1;
  495.   packlen = datalen + MAXIPLEN + MAXICMPLEN;
  496.   if (!(packet = (u_char *)malloc((u_int)packlen))) {
  497.     (void)fprintf(stderr, "ping: out of memory.\n");
  498.     exit(1);
  499.   }
  500.   if (!(options & F_PINGFILLED))
  501.     for (i = 8; i < datalen; ++i)
  502.       *datap++ = i;
  503.  
  504.   ident = getpid() & 0xFFFF;
  505.  
  506.   if (!(proto = getprotobyname("icmp"))) {
  507.     (void)fprintf(stderr, "ping: unknown protocol icmp.\n");
  508.     exit(1);
  509.   }
  510.  
  511. #ifdef AMIGA
  512.   signal(SIGINT, SIG_IGN);
  513.   atexit(clean_timer);
  514.  
  515.   timerport = CreateMsgPort();
  516.   if (!timerport) {
  517.     (void)fprintf(stderr, "ping: could not create timer port.\n");
  518.     exit(1);
  519.   }
  520.   timermask = 1<<timerport->mp_SigBit;
  521.  
  522.   timermsg = CreateIORequest(timerport, sizeof(*timermsg));
  523.   if (!timermsg) {
  524.     (void)fprintf(stderr, "ping: could not create timer message.\n");
  525.     exit(1);
  526.   }
  527.  
  528.   if (notopen = OpenDevice("timer.device", UNIT_MICROHZ, 
  529.          (struct IORequest *)timermsg, 0)) {
  530.     (void)fprintf(stderr, "ping: could not open timer device.\n");
  531.     exit(1);
  532.   }
  533.  
  534.   timermsg->tr_node.io_Command = TR_ADDREQUEST;
  535.   timermsg->tr_time.tv_secs = 1L;
  536.   timermsg->tr_time.tv_micro = 0L;
  537.   /* don't confuse CheckIO */
  538.   timermsg->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG; 
  539.   SetSocketSignals(timermask | SIGBREAKF_CTRL_C, 0L, 0L);
  540. #endif
  541.  
  542.   if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  543.     perror("ping: socket");
  544.     exit(1);
  545.   }
  546.   hold = 1;
  547.   if (options & F_SO_DEBUG)
  548.     (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
  549.              sizeof(hold));
  550.   if (options & F_SO_DONTROUTE)
  551.     (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
  552.              sizeof(hold));
  553.  
  554.   /* record route option */
  555.   if (options & F_RROUTE) {
  556. #ifdef IP_OPTIONS
  557.     rspace[IPOPT_OPTVAL] = IPOPT_RR;
  558.     rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  559.     rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  560.     if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
  561.            sizeof(rspace)) < 0) {
  562.       perror("ping: record route");
  563.       exit(1);
  564.     }
  565. #else
  566.     (void)fprintf(stderr, 
  567.           "ping: record route not available in this implementation.\n");
  568.     exit(1);
  569. #endif                /* IP_OPTIONS */
  570.   }
  571.  
  572.   /*
  573.    * When pinging the broadcast address, you can get a lot of answers.
  574.    * Doing something so evil is useful if you are trying to stress the
  575.    * ethernet, or just want to fill the arp cache to get some stuff for
  576.    * /etc/ethers.
  577.    */
  578.   hold = 48 * 1024;
  579.   (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
  580.            sizeof(hold));
  581.  
  582.   if (to->sin_family == AF_INET)
  583.     (void)printf("PING %s (%s): %d data bytes\n", hostname,
  584.          inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
  585.          datalen);
  586.   else
  587.     (void)printf("PING %s: %d data bytes\n", hostname, datalen);
  588.  
  589. #ifndef AMIGA
  590.   (void)signal(SIGINT, finish);
  591.   (void)signal(SIGALRM, catcher);
  592. #endif
  593.  
  594.   while (preload--)        /* fire off them quickies */
  595.     pinger();
  596.  
  597.   if ((options & F_FLOOD) == 0)
  598.     catcher();            /* start things going */
  599.  
  600.   for (;;) {
  601.     struct sockaddr_in from;
  602.     register int cc;
  603.     int fromlen;
  604.  
  605. #ifdef AMIGA
  606.     /* Check for special signals */
  607.     ULONG sm = SetSignal(0L, timermask | SIGBREAKF_CTRL_C);
  608.     if (sm & SIGBREAKF_CTRL_C)
  609.       finish();
  610.     if (sm & timermask && GetMsg(timerport))
  611.       catcher();
  612. #endif    
  613.  
  614.     if (options & F_FLOOD) {
  615.       pinger();
  616.       timeout.tv_sec = 0;
  617.       timeout.tv_usec = 10000;
  618.       fdmask = 1 << s;
  619.       if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
  620.          (fd_set *)NULL, &timeout) < 1)
  621.     continue;
  622.     }
  623.     fromlen = sizeof(from);
  624.     if ((cc = recvfrom(s, (char *)packet, packlen, 0,
  625.                (struct sockaddr *)&from, &fromlen)) < 0) {
  626.       if (errno == EINTR)
  627.     continue;
  628.       perror("ping: recvfrom");
  629.       continue;
  630.     }
  631.     pr_pack((char *)packet, cc, &from);
  632.     if (npackets && nreceived >= npackets)
  633.       break;
  634.   }
  635.   finish();
  636.   /* NOTREACHED */
  637. }
  638.  
  639. /*
  640.  * catcher --
  641.  *    This routine causes another PING to be transmitted, and then
  642.  * schedules another SIGALRM for 1 second from now.
  643.  * 
  644.  * bug --
  645.  *    Our sense of time will slowly skew (i.e., packets will not be
  646.  * launched exactly at 1-second intervals).  This does not affect the
  647.  * quality of the delay and loss statistics.
  648.  *
  649.  * notes --
  650.  *      This routine uses timer.device in Amiga implementation instead 
  651.  * of SIGALRM. 
  652.  */
  653. void
  654. catcher()
  655. {
  656. #ifdef AMIGA
  657.   static int waittime = 0;
  658.  
  659.   if (waittime) 
  660.     finish();
  661.  
  662.   pinger();
  663.   
  664.   if (!npackets || ntransmitted < npackets) {
  665.     timermsg->tr_time.tv_sec = interval;
  666.     SendIO((struct IORequest*)timermsg);
  667.   } else {
  668.     if (nreceived) {
  669.       waittime = 2 * tmax / 1000;
  670.       if (!waittime)
  671.     waittime = 1;
  672.     } else
  673.       waittime = MAXWAIT;
  674.     timermsg->tr_time.tv_sec = waittime;
  675.     SendIO((struct IORequest*)timermsg);
  676.   }
  677. #else
  678.     int waittime;
  679.  
  680.     pinger();
  681.     (void)signal(SIGALRM, catcher);
  682.     if (!npackets || ntransmitted < npackets)
  683.         alarm((u_int)interval);
  684.     else {
  685.         if (nreceived) {
  686.             waittime = 2 * tmax / 1000;
  687.             if (!waittime)
  688.                 waittime = 1;
  689.         } else
  690.             waittime = MAXWAIT;
  691.         (void)signal(SIGALRM, finish);
  692.         (void)alarm((u_int)waittime);
  693.     }
  694. #endif
  695. }
  696.  
  697. /*
  698.  * pinger --
  699.  *     Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  700.  * will be added on by the kernel.  The ID field is our process ID,
  701.  * and the sequence number is an ascending integer.  The first 8 bytes
  702.  * of the data portion are used to hold a UNIX "timeval" struct in native
  703.  * byte-order, to compute the round-trip time.
  704.  */
  705. void
  706. pinger()
  707. {
  708.     register struct icmp *icp;
  709.     register int cc;
  710.     int i;
  711.  
  712.     icp = (struct icmp *)outpack;
  713.     icp->icmp_type = ICMP_ECHO;
  714.     icp->icmp_code = 0;
  715.     icp->icmp_cksum = 0;
  716.     icp->icmp_seq = ntransmitted++;
  717.     icp->icmp_id = ident;            /* ID */
  718.  
  719.     CLR(icp->icmp_seq % mx_dup_ck);
  720.  
  721.     if (timing)
  722. #ifdef AMIGA
  723.         (void)ReadEClock((struct EClockVal *)&outpack[8]);
  724. #else
  725.         (void)gettimeofday((struct timeval *)&outpack[8],
  726.             (struct timezone *)NULL);
  727. #endif
  728.     cc = datalen + 8;            /* skips ICMP portion */
  729.  
  730.     /* compute ICMP checksum here */
  731.     icp->icmp_cksum = in_cksum((u_short *)icp, cc);
  732.  
  733.     i = sendto(s, (char *)outpack, cc, 0, &whereto,
  734.         sizeof(struct sockaddr));
  735.  
  736.     if (i < 0 || i != cc)  {
  737.         if (i < 0)
  738.             perror("ping: sendto");
  739.         (void)printf("ping: wrote %s %d chars, ret=%d\n",
  740.             hostname, cc, i);
  741.     }
  742.     if (!(options & F_QUIET) && options & F_FLOOD)
  743.         (void)write(1, &DOT, 1);
  744. }
  745.  
  746. /*
  747.  * pr_pack --
  748.  *    Print out the packet, if it came from us.  This logic is necessary
  749.  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  750.  * which arrive ('tis only fair).  This permits multiple copies of this
  751.  * program to be run without having intermingled output (or statistics!).
  752.  */
  753. void
  754. pr_pack(buf, cc, from)
  755.     char *buf;
  756.     int cc;
  757.     struct sockaddr_in *from;
  758. {
  759.     register struct icmp *icp;
  760.     register u_long l;
  761.     register int i, j;
  762.     register u_char *cp,*dp;
  763.     static int old_rrlen;
  764.     static char old_rr[MAX_IPOPTLEN];
  765.     struct ip *ip;
  766.     struct timeval tv, *tp;
  767.     long triptime;
  768.     int hlen, dupflag;
  769.  
  770. #ifdef AMIGA
  771.     ULONG efreq = ReadEClock((struct EClockVal *)&tv);
  772. #else
  773.     (void)gettimeofday(&tv, (struct timezone *)NULL);
  774. #endif
  775.     /* Check the IP header */
  776.     ip = (struct ip *)buf;
  777.     hlen = ip->ip_hl << 2;
  778.     if (cc < hlen + ICMP_MINLEN) {
  779.         if (options & F_VERBOSE)
  780.             (void)fprintf(stderr,
  781.               "ping: packet too short (%d bytes) from %s\n", cc,
  782.               inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
  783.         return;
  784.     }
  785.  
  786.     /* Now the ICMP part */
  787.     cc -= hlen;
  788.     icp = (struct icmp *)(buf + hlen);
  789.     if (icp->icmp_type == ICMP_ECHOREPLY) {
  790.         if (icp->icmp_id != ident)
  791.             return;            /* 'Twas not our ECHO */
  792.         ++nreceived;
  793.         if (timing) {
  794. #ifndef icmp_data
  795.             tp = (struct timeval *)&icp->icmp_ip;
  796. #else
  797.             tp = (struct timeval *)icp->icmp_data;
  798. #endif
  799. #ifdef AMIGA
  800.             /* EClockVal is actually a unsigned long long */  
  801.             if (tv.tv_micro < tp->tv_micro)
  802.               tv.tv_sec--;
  803.             tv.tv_micro -= tp->tv_micro;
  804.             tv.tv_secs  -= tp->tv_secs;
  805.             triptime = tv.tv_micro / (efreq / 1000);
  806.             if (tv.tv_secs)
  807.               triptime += tv.tv_sec * 250 * ((1<<30) / efreq);
  808. #else
  809.             tvsub(&tv, tp);
  810.             triptime = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
  811. #endif
  812.             tsum += triptime;
  813.             if (triptime < tmin)
  814.                 tmin = triptime;
  815.             if (triptime > tmax)
  816.                 tmax = triptime;
  817.         }
  818.  
  819.         if (TST(icp->icmp_seq % mx_dup_ck)) {
  820.             ++nrepeats;
  821.             --nreceived;
  822.             dupflag = 1;
  823.         } else {
  824.             SET(icp->icmp_seq % mx_dup_ck);
  825.             dupflag = 0;
  826.         }
  827.  
  828.         if (options & F_QUIET)
  829.             return;
  830.  
  831.         if (options & F_FLOOD)
  832.             (void)write(1, &BSPACE, 1);
  833.         else {
  834.             (void)printf("%d bytes from %s: icmp_seq=%u", cc,
  835.                inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
  836.                icp->icmp_seq);
  837.             (void)printf(" ttl=%d", ip->ip_ttl);
  838.             if (timing)
  839.                 (void)printf(" time=%ld ms", triptime);
  840.             if (dupflag)
  841.                 (void)printf(" (DUP!)");
  842.             /* check the data */
  843.             cp = (u_char*)&icp->icmp_data[8];
  844.             dp = &outpack[8 + sizeof(struct timeval)];
  845.             for (i = 8; i < datalen; ++i, ++cp, ++dp) {
  846.                 if (*cp != *dp) {
  847.     (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
  848.         i, *dp, *cp);
  849.                     cp = (u_char*)&icp->icmp_data[0];
  850.                     for (i = 8; i < datalen; ++i, ++cp) {
  851.                         if ((i % 32) == 8)
  852.                             (void)printf("\n\t");
  853.                         (void)printf("%x ", *cp);
  854.                     }
  855.                     break;
  856.                 }
  857.             }
  858.         }
  859.     } else {
  860.         /* We've got something other than an ECHOREPLY */
  861.         if (!(options & F_VERBOSE))
  862.             return;
  863.         (void)printf("%d bytes from %s: ", cc,
  864.             pr_addr(from->sin_addr.s_addr));
  865.         pr_icmph(icp);
  866.     }
  867.  
  868.     /* Display any IP options */
  869.     cp = (u_char *)buf + sizeof(struct ip);
  870.  
  871.     for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
  872.         switch (*cp) {
  873.         case IPOPT_EOL:
  874.             hlen = 0;
  875.             break;
  876.         case IPOPT_LSRR:
  877.             (void)printf("\nLSRR: ");
  878.             hlen -= 2;
  879.             j = *++cp;
  880.             ++cp;
  881.             if (j > IPOPT_MINOFF)
  882.                 for (;;) {
  883.                     l = *++cp;
  884.                     l = (l<<8) + *++cp;
  885.                     l = (l<<8) + *++cp;
  886.                     l = (l<<8) + *++cp;
  887.                     if (l == 0)
  888.                         (void)printf("\t0.0.0.0");
  889.                 else
  890.                     (void)printf("\t%s", pr_addr(ntohl(l)));
  891.                 hlen -= 4;
  892.                 j -= 4;
  893.                 if (j <= IPOPT_MINOFF)
  894.                     break;
  895.                 (void)putchar('\n');
  896.             }
  897.             break;
  898.         case IPOPT_RR:
  899.             j = *++cp;        /* get length */
  900.             i = *++cp;        /* and pointer */
  901.             hlen -= 2;
  902.             if (i > j)
  903.                 i = j;
  904.             i -= IPOPT_MINOFF;
  905.             if (i <= 0)
  906.                 continue;
  907.             if (i == old_rrlen
  908.                 && cp == (u_char *)buf + sizeof(struct ip) + 2
  909.                 && !bcmp((char *)cp, old_rr, i)
  910.                 && !(options & F_FLOOD)) {
  911.                 (void)printf("\t(same route)");
  912.                 i = ((i + 3) / 4) * 4;
  913.                 hlen -= i;
  914.                 cp += i;
  915.                 break;
  916.             }
  917.             old_rrlen = i;
  918.             bcopy((char *)cp, old_rr, i);
  919.             (void)printf("\nRR: ");
  920.             for (;;) {
  921.                 l = *++cp;
  922.                 l = (l<<8) + *++cp;
  923.                 l = (l<<8) + *++cp;
  924.                 l = (l<<8) + *++cp;
  925.                 if (l == 0)
  926.                     (void)printf("\t0.0.0.0");
  927.                 else
  928.                     (void)printf("\t%s", pr_addr(ntohl(l)));
  929.                 hlen -= 4;
  930.                 i -= 4;
  931.                 if (i <= 0)
  932.                     break;
  933.                 (void)putchar('\n');
  934.             }
  935.             break;
  936.         case IPOPT_NOP:
  937.             (void)printf("\nNOP");
  938.             break;
  939.         default:
  940.             (void)printf("\nunknown option %x", *cp);
  941.             break;
  942.         }
  943.     if (!(options & F_FLOOD)) {
  944.         (void)putchar('\n');
  945.         (void)fflush(stdout);
  946.     }
  947. }
  948.  
  949. /*
  950.  * in_cksum --
  951.  *    Checksum routine for Internet Protocol family headers (C Version)
  952.  */
  953. int
  954. in_cksum(addr, len)
  955.     u_short *addr;
  956.     int len;
  957. {
  958.     register int nleft = len;
  959.     register u_short *w = addr;
  960.     register int sum = 0;
  961.     u_short answer = 0;
  962.  
  963.     /*
  964.      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
  965.      * sequential 16 bit words to it, and at the end, fold back all the
  966.      * carry bits from the top 16 bits into the lower 16 bits.
  967.      */
  968.     while (nleft > 1)  {
  969.         sum += *w++;
  970.         nleft -= 2;
  971.     }
  972.  
  973.     /* mop up an odd byte, if necessary */
  974.     if (nleft == 1) {
  975.         *(u_char *)(&answer) = *(u_char *)w ;
  976.         sum += answer;
  977.     }
  978.  
  979.     /* add back carry outs from top 16 bits to low 16 bits */
  980.     sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  981.     sum += (sum >> 16);            /* add carry */
  982.     answer = ~sum;                /* truncate to 16 bits */
  983.     return(answer);
  984. }
  985.  
  986. /*
  987.  * tvsub --
  988.  *    Subtract 2 timeval structs:  out = out - in.  Out is assumed to
  989.  * be >= in.
  990.  */
  991. void
  992. tvsub(out, in)
  993.     register struct timeval *out, *in;
  994. {
  995.     if ((out->tv_usec -= in->tv_usec) < 0) {
  996.         --out->tv_sec;
  997.         out->tv_usec += 1000000;
  998.     }
  999.     out->tv_sec -= in->tv_sec;
  1000. }
  1001.  
  1002. /*
  1003.  * finish --
  1004.  *    Print out statistics, and give up.
  1005.  */
  1006. void
  1007. finish()
  1008. {
  1009.     (void)signal(SIGINT, SIG_IGN);
  1010.     (void)putchar('\n');
  1011.     (void)fflush(stdout);
  1012.     (void)printf("--- %s ping statistics ---\n", hostname);
  1013.     (void)printf("%ld packets transmitted, ", ntransmitted);
  1014.     (void)printf("%ld packets received, ", nreceived);
  1015.     if (nrepeats)
  1016.         (void)printf("+%ld duplicates, ", nrepeats);
  1017.     if (ntransmitted)
  1018.         if (nreceived > ntransmitted)
  1019.             (void)printf("-- somebody's printing up packets!");
  1020.         else
  1021.             (void)printf("%d%% packet loss",
  1022.                 (int) (((ntransmitted - nreceived) * 100) /
  1023.                 ntransmitted));
  1024.     (void)putchar('\n');
  1025.     if (nreceived && timing)
  1026.         (void)printf("round-trip min/avg/max = %ld/%lu/%ld ms\n",
  1027.             tmin, tsum / (nreceived + nrepeats), tmax);
  1028.     exit(0);
  1029. }
  1030.  
  1031. #ifdef notdef
  1032. static char *ttab[] = {
  1033.     "Echo Reply",        /* ip + seq + udata */
  1034.     "Dest Unreachable",    /* net, host, proto, port, frag, sr + IP */
  1035.     "Source Quench",    /* IP */
  1036.     "Redirect",        /* redirect type, gateway, + IP  */
  1037.     "Echo",
  1038.     "Time Exceeded",    /* transit, frag reassem + IP */
  1039.     "Parameter Problem",    /* pointer + IP */
  1040.     "Timestamp",        /* id + seq + three timestamps */
  1041.     "Timestamp Reply",    /* " */
  1042.     "Info Request",        /* id + sq */
  1043.     "Info Reply"        /* " */
  1044. };
  1045. #endif
  1046.  
  1047. /*
  1048.  * pr_icmph --
  1049.  *    Print a descriptive string about an ICMP header.
  1050.  */
  1051. void
  1052. pr_icmph(icp)
  1053.     struct icmp *icp;
  1054. {
  1055.     switch(icp->icmp_type) {
  1056.     case ICMP_ECHOREPLY:
  1057.         (void)printf("Echo Reply\n");
  1058.         /* XXX ID + Seq + Data */
  1059.         break;
  1060.     case ICMP_UNREACH:
  1061.         switch(icp->icmp_code) {
  1062.         case ICMP_UNREACH_NET:
  1063.             (void)printf("Destination Net Unreachable\n");
  1064.             break;
  1065.         case ICMP_UNREACH_HOST:
  1066.             (void)printf("Destination Host Unreachable\n");
  1067.             break;
  1068.         case ICMP_UNREACH_PROTOCOL:
  1069.             (void)printf("Destination Protocol Unreachable\n");
  1070.             break;
  1071.         case ICMP_UNREACH_PORT:
  1072.             (void)printf("Destination Port Unreachable\n");
  1073.             break;
  1074.         case ICMP_UNREACH_NEEDFRAG:
  1075.             (void)printf("frag needed and DF set\n");
  1076.             break;
  1077.         case ICMP_UNREACH_SRCFAIL:
  1078.             (void)printf("Source Route Failed\n");
  1079.             break;
  1080.         default:
  1081.             (void)printf("Dest Unreachable, Bad Code: %d\n",
  1082.                 icp->icmp_code);
  1083.             break;
  1084.         }
  1085.         /* Print returned IP header information */
  1086. #ifndef icmp_data
  1087.         pr_retip(&icp->icmp_ip);
  1088. #else
  1089.         pr_retip((struct ip *)icp->icmp_data);
  1090. #endif
  1091.         break;
  1092.     case ICMP_SOURCEQUENCH:
  1093.         (void)printf("Source Quench\n");
  1094. #ifndef icmp_data
  1095.         pr_retip(&icp->icmp_ip);
  1096. #else
  1097.         pr_retip((struct ip *)icp->icmp_data);
  1098. #endif
  1099.         break;
  1100.     case ICMP_REDIRECT:
  1101.         switch(icp->icmp_code) {
  1102.         case ICMP_REDIRECT_NET:
  1103.             (void)printf("Redirect Network");
  1104.             break;
  1105.         case ICMP_REDIRECT_HOST:
  1106.             (void)printf("Redirect Host");
  1107.             break;
  1108.         case ICMP_REDIRECT_TOSNET:
  1109.             (void)printf("Redirect Type of Service and Network");
  1110.             break;
  1111.         case ICMP_REDIRECT_TOSHOST:
  1112.             (void)printf("Redirect Type of Service and Host");
  1113.             break;
  1114.         default:
  1115.             (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
  1116.             break;
  1117.         }
  1118.         (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
  1119. #ifndef icmp_data
  1120.         pr_retip(&icp->icmp_ip);
  1121. #else
  1122.         pr_retip((struct ip *)icp->icmp_data);
  1123. #endif
  1124.         break;
  1125.     case ICMP_ECHO:
  1126.         (void)printf("Echo Request\n");
  1127.         /* XXX ID + Seq + Data */
  1128.         break;
  1129.     case ICMP_TIMXCEED:
  1130.         switch(icp->icmp_code) {
  1131.         case ICMP_TIMXCEED_INTRANS:
  1132.             (void)printf("Time to live exceeded\n");
  1133.             break;
  1134.         case ICMP_TIMXCEED_REASS:
  1135.             (void)printf("Frag reassembly time exceeded\n");
  1136.             break;
  1137.         default:
  1138.             (void)printf("Time exceeded, Bad Code: %d\n",
  1139.                 icp->icmp_code);
  1140.             break;
  1141.         }
  1142. #ifndef icmp_data
  1143.         pr_retip(&icp->icmp_ip);
  1144. #else
  1145.         pr_retip((struct ip *)icp->icmp_data);
  1146. #endif
  1147.         break;
  1148.     case ICMP_PARAMPROB:
  1149.         (void)printf("Parameter problem: pointer = 0x%02x\n",
  1150.             icp->icmp_hun.ih_pptr);
  1151. #ifndef icmp_data
  1152.         pr_retip(&icp->icmp_ip);
  1153. #else
  1154.         pr_retip((struct ip *)icp->icmp_data);
  1155. #endif
  1156.         break;
  1157.     case ICMP_TSTAMP:
  1158.         (void)printf("Timestamp\n");
  1159.         /* XXX ID + Seq + 3 timestamps */
  1160.         break;
  1161.     case ICMP_TSTAMPREPLY:
  1162.         (void)printf("Timestamp Reply\n");
  1163.         /* XXX ID + Seq + 3 timestamps */
  1164.         break;
  1165.     case ICMP_IREQ:
  1166.         (void)printf("Information Request\n");
  1167.         /* XXX ID + Seq */
  1168.         break;
  1169.     case ICMP_IREQREPLY:
  1170.         (void)printf("Information Reply\n");
  1171.         /* XXX ID + Seq */
  1172.         break;
  1173. #ifdef ICMP_MASKREQ
  1174.     case ICMP_MASKREQ:
  1175.         (void)printf("Address Mask Request\n");
  1176.         break;
  1177. #endif
  1178. #ifdef ICMP_MASKREPLY
  1179.     case ICMP_MASKREPLY:
  1180.         (void)printf("Address Mask Reply\n");
  1181.         break;
  1182. #endif
  1183.     default:
  1184.         (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
  1185.     }
  1186. }
  1187.  
  1188. /*
  1189.  * pr_iph --
  1190.  *    Print an IP header with options.
  1191.  */
  1192. void
  1193. pr_iph(ip)
  1194.     struct ip *ip;
  1195. {
  1196.     int hlen;
  1197.     u_char *cp;
  1198.  
  1199.     hlen = ip->ip_hl << 2;
  1200.     cp = (u_char *)ip + 20;        /* point to options */
  1201.  
  1202.     (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
  1203.     (void)printf(" %1x  %1x  %02x %04x %04x",
  1204.         ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
  1205.     (void)printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
  1206.         (ip->ip_off) & 0x1fff);
  1207.     (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
  1208.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
  1209.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
  1210.     /* dump and option bytes */
  1211.     while (hlen-- > 20) {
  1212.         (void)printf("%02x", *cp++);
  1213.     }
  1214.     (void)putchar('\n');
  1215. }
  1216.  
  1217. /*
  1218.  * pr_addr --
  1219.  *    Return an ascii host address as a dotted quad and optionally with
  1220.  * a hostname.
  1221.  */
  1222. char *
  1223. pr_addr(l)
  1224.     u_long l;
  1225. {
  1226.     struct hostent *hp;
  1227.     static char buf[80];
  1228.  
  1229.     if ((options & F_NUMERIC) ||
  1230.         !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
  1231.         (void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
  1232.     else
  1233.         (void)sprintf(buf, "%s (%s)", hp->h_name,
  1234.             inet_ntoa(*(struct in_addr *)&l));
  1235.     return(buf);
  1236. }
  1237.  
  1238. /*
  1239.  * pr_retip --
  1240.  *    Dump some info on a returned (via ICMP) IP packet.
  1241.  */
  1242. void
  1243. pr_retip(ip)
  1244.     struct ip *ip;
  1245. {
  1246.     int hlen;
  1247.     u_char *cp;
  1248.  
  1249.     pr_iph(ip);
  1250.     hlen = ip->ip_hl << 2;
  1251.     cp = (u_char *)ip + hlen;
  1252.  
  1253.     if (ip->ip_p == 6)
  1254.         (void)printf("TCP: from port %u, to port %u (decimal)\n",
  1255.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1256.     else if (ip->ip_p == 17)
  1257.         (void)printf("UDP: from port %u, to port %u (decimal)\n",
  1258.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1259. }
  1260.  
  1261. void
  1262. fill(bp, patp)
  1263.     char *bp, *patp;
  1264. {
  1265.     register int ii, jj, kk;
  1266.     int pat[16];
  1267.     char *cp;
  1268.  
  1269.     for (cp = patp; *cp; cp++)
  1270.         if (!isxdigit(*cp)) {
  1271.             (void)fprintf(stderr,
  1272.                 "ping: patterns must be specified as hex digits.\n");
  1273.             exit(1);
  1274.         }
  1275.     ii = sscanf(patp,
  1276.         "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  1277.         &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
  1278.         &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
  1279.         &pat[13], &pat[14], &pat[15]);
  1280.  
  1281.     if (ii > 0)
  1282.         for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii)
  1283.             for (jj = 0; jj < ii; ++jj)
  1284.                 bp[jj + kk] = pat[jj];
  1285.     if (!(options & F_QUIET)) {
  1286.         (void)printf("PATTERN: 0x");
  1287.         for (jj = 0; jj < ii; ++jj)
  1288.             (void)printf("%02x", bp[jj] & 0xFF);
  1289.         (void)printf("\n");
  1290.     }
  1291. }
  1292.  
  1293. void
  1294. usage()
  1295. {
  1296.     (void)fprintf(stderr,
  1297.         "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n"
  1298.               "\t[-p pattern] [-s packetsize] host\n");
  1299.     exit(1);
  1300. }
  1301.